#ifndef _LINUX_MSDOS_FS_H
#define _LINUX_MSDOS_FS_H
#pragma pack(1)

#include <fs/types.h>

#define MSDOS_ROOT_INO	1	/* == MINIX_ROOT_INO */
#define MSDOS_DIR_BITS	5	/* log2(sizeof(struct msdos_dir_entry)) */

/* directory limit */
#define FAT_MAX_DIR_ENTRIES	(65536)
#define FAT_MAX_DIR_SIZE	(FAT_MAX_DIR_ENTRIES << MSDOS_DIR_BITS)

#define ATTR_NONE	0	/* no attribute bits */
#define ATTR_RO		1	/* read-only */
#define ATTR_HIDDEN	2	/* hidden */
#define ATTR_SYS	4	/* system */
#define ATTR_VOLUME	8	/* volume label */
#define ATTR_DIR	16	/* directory */
#define ATTR_ARCH	32	/* archived */

/* attribute bits that are copied "as is" */
#define ATTR_UNUSED	(ATTR_VOLUME | ATTR_ARCH | ATTR_SYS | ATTR_HIDDEN)

#define DELETED_FLAG	0xe5	/* marks file as deleted when in name[0] */
#define IS_FREE(n)	(!*(n) || *(n) == DELETED_FLAG)

#define MSDOS_NAME      11      /* maximum name length */
#define MSDOS_LONGNAME  256     /* maximum name length */
#define MSDOS_SLOTS     21      /* max # of slots for short and long names */
#define MSDOS_DOT       ".          "   /* ".", padded to MSDOS_NAME chars */
#define MSDOS_DOTDOT    "..         "   /* "..", padded to MSDOS_NAME chars */

/* start of data cluster's entry (number of reserved clusters) */
#define FAT_START_ENT	2

/* maximum number of clusters */
#define MAX_FAT12	0xFF4
#define MAX_FAT16	0xFFF4
#define MAX_FAT32	0x0FFFFFF6
#define MAX_FAT(s)	(MSDOS_SB(s)->fat_bits == 32 ? MAX_FAT32 : \
	MSDOS_SB(s)->fat_bits == 16 ? MAX_FAT16 : MAX_FAT12)

/* bad cluster mark */
#define BAD_FAT12	0xFF7
#define BAD_FAT16	0xFFF7
#define BAD_FAT32	0x0FFFFFF7

/* standard EOF */
#define EOF_FAT12	0xFFF
#define EOF_FAT16	0xFFFF
#define EOF_FAT32	0x0FFFFFFF

#define FAT_ENT_FREE	(0)
#define FAT_ENT_BAD	(BAD_FAT32)
#define FAT_ENT_EOF	(EOF_FAT32)

/* standard EOF */
#define FAT_FSINFO_SIG1	0x41615252
#define FAT_FSINFO_SIG2	0x61417272
#define IS_FSINFO(x)	(le32_to_cpu((x)->signature1) == FAT_FSINFO_SIG1 \
			 && le32_to_cpu((x)->signature2) == FAT_FSINFO_SIG2)

struct fat_boot_sector {
	__s8	ignored[3];	/* Boot strap short or near jump */
	__s8	system_id[8];	/* Name - can be used to special case
				   partition manager volumes */
	__u8	sector_size[2];	/* 0xb bytes per logical sector */
	__u8	sec_per_clus;	/* 0xd sectors/cluster */
	__u16	reserved;	/* 0xe reserved sectors */
	__u8	fats;		/* 0x10 number of FATs */
	__u8	dir_entries[2];	/* 0x11 root directory entries */
	__u8	sectors[2];	/* 0x13 number of sectors */
	__u8	media;		/* 0x15 media code (unused) */
	__u16	fat_length;	/* 0x16 sectors/FAT */
	__u16	secs_track;	/* 0x18 sectors per track */
	__u16	heads;		/* 0x1a number of heads */
	__u32	hidden;		/* 0x1c hidden sectors (unused) */
	__u32	total_sect;	/* 0x20 number of sectors (if sectors == 0) */

	/* The following fields are only used by FAT32 */
	__u32	fat32_length;	/* 0x24 sectors/FAT */
	__u16	flags;		/* 0x28 bit 8: fat mirroring, low 4: active fat */
	__u8	version[2];	/* 0x2a major, minor filesystem version */
	__u32	root_cluster;	/* 0x2c first cluster in root directory */
	__u16	info_sector;	/* 0x30 filesystem info sector */
	__u16	backup_boot;	/* 0x32 backup boot sector */
	__u16	reserved2[6];	/* Unused */
};

struct msdos_dir_entry {
	__u8    name[MSDOS_NAME];/* name and extension */
	__u8    attr;           /* attribute bits */
	__u8    lcase;          /* Case for base and extension */
	__u8    ctime_cs;       /* Creation time, centiseconds (0-199) */
	__le16  ctime;          /* Creation time */
	__le16  cdate;          /* Creation date */
	__le16  adate;          /* Last access date */
	__le16  starthi;        /* High 16 bits of cluster in FAT32 */
	__le16  time,date,start;/* time, date and first cluster */
	__le32  size;           /* file size (in bytes) */
};

struct fat_boot_fsinfo {
	__le32   signature1;	/* 0x41615252L */
	__le32   reserved1[120];	/* Nothing as far as I can tell */
	__le32   signature2;	/* 0x61417272L */
	__le32   free_clusters;	/* Free cluster count.  -1 if unknown */
	__le32   next_cluster;	/* Most recently allocated cluster */
	__le32   reserved2[4];
};

struct fat_boot_bsx {
	__u8     drive;		    /* drive number */
	__u8     reserved1;
	__u8     signature;	    /* extended boot signature */
	__u8     vol_id[4];     /* volume ID */
	__u8     vol_label[11]; /* volume label */
	__u8     type[8];       /* file system type */
};
#define FAT16_BSX_OFFSET	36 /* offset of fat_boot_bsx in FAT12 and FAT16 */
#define FAT32_BSX_OFFSET	64 /* offset of fat_boot_bsx in FAT32 */

/* media of boot sector */
static inline int fat_valid_media(u8 media)
{
	return 0xf8 <= media || media == 0xf0;
}

#endif
